// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

#include "Symbole.h"

////////////////////////////////////////////////////////////////////////////////
class Noeud {
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
  public:
    virtual int  getValeur() =0 ; // méthode pure (non implémentée) qui rend la classe abstraite
    virtual void afficher(unsigned short indentation=0) { cout << setw(4*indentation) << " "; }
      // pour afficher un noeud avec un décalage (indentation) proportionnel à son niveau dans l'arbre
    virtual void traduire(unsigned short indentation=0) { cout << setw(4*indentation) << " "; }

    virtual ~Noeud() {} // présence d'un destructeur virtuel conseillée dans les classes abstraites
};

////////////////////////////////////////////////////////////////////////////////
class NoeudSeqInst : public Noeud {
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
  public:
     NoeudSeqInst();   // construit une séquence d'instruction vide
    ~NoeudSeqInst() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation=0); // affiche la séquence d'instructions
    void traduire(unsigned short indentation=0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction);  // ajoute une instruction à la séquence

  private:
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};

////////////////////////////////////////////////////////////////////////////////
class NoeudAffectation : public Noeud {
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
  public:
     NoeudAffectation(Noeud* variable, Noeud* expression); // construit une affectation
    ~NoeudAffectation() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation
    void traduire(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurBinaire : public Noeud {
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
  public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
     // construit une opération binaire : operandeGauche operateur OperandeDroit
   ~NoeudOperateurBinaire() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération
    void traduire(unsigned short indentation=0); // affiche l'opération

  private:
    Symbole operateur;
    Noeud*  operandeGauche;
    Noeud*  operandeDroit;
};

/////////////////////////////////////////////////////////////////////////
class NoeudCondition: public Noeud {
// classe pour représenter un noeud "Condition"
// Super classe des classes : NoeudInstSi, NoeudInstSuivant
// Elle est composé de 2 fils :
//    - le vecteur des valeurs ou d'expressions booléenne des conditions
//    - le vecteur des séquence d'instructions respectives pour les conditions
  public:
     NoeudCondition (Noeud* exp, Noeud* tabInst);
    ~NoeudCondition() {}
    void ajouterCasExp(Noeud* casExpBool);
    void ajouterCasTabInst(Noeud* casTabInst);

  protected:
    vector<Noeud *> casExp;
    vector<Noeud *> casTabInst;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstSi : public NoeudCondition {
// classe pour représenter un noeud "si()..sinonsi()..sinon..finsi"
// Elle est composé de 2 fils :
//    - le vecteur des expressions booléennes des "si" et "sinonsi"
//    - le vecteur des séquences d'instructions des "si", "sinonsi" et "sinon"
  public:
     NoeudInstSi(Noeud* expBool, Noeud* tabInst);
    ~NoeudInstSi() {}
    int getValeur();
    void afficher(unsigned short indentation=0);
    void traduire(unsigned short indentation=0);
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstSelon : public NoeudCondition {
// classe pour représenter un noeud "selon(A) cas X : .. defaut: .. finselon"
// Elle est composé de 2 fils :
//    - le vecteur des valeurs des "cas"
//    - le vecteur des séquences d'instructions des "cas" et "defaut"
  public:
     NoeudInstSelon(Noeud* expBool, Noeud* tabInst, Noeud* variable);
    ~NoeudInstSelon() {}
    int getValeur();
    void afficher(unsigned short indentation=0);
    void traduire(unsigned short indentation=0);
    
  private:
    Noeud* variable;
};

/////////////////////////////////////////////////////////////////////////
class NoeudBoucle: public Noeud {
// classe pour représenter un noeud "Boucle"
// Super classe des classes : NoeudInstTq, NoeudInstRepeter
// Elle est composé de 2 fils :
//    - l'expression booléenne de boucle
//    - la séquence d'instructions de la boucle
  public:
     NoeudBoucle (Noeud* expBool, Noeud* tabInst);
    ~NoeudBoucle() {}

  protected:
    Noeud* expBool;
    Noeud* tabInst;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstTq : public NoeudBoucle {
// classe pour représenter un noeud "tanque()..fintanque"
// Elle est composé de 2 fils :
//    - l'expression booléenne de boucle
//    - la séquence d'instructions de la boucle
  public:
    NoeudInstTq(Noeud* expBool, Noeud* tabInst);
   ~NoeudInstTq() {}
    int getValeur();
    void afficher(unsigned short indentation=0); // affiche l'opération
    void traduire(unsigned short indentation=0); // affiche l'opération
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstRepeter : public NoeudBoucle {
// classe pour représenter un noeud "repeter..jusqua()"
// Elle est composé de 2 fils :
//    - l'expression booléenne de boucle
//    - la séquence d'instructions de la boucle
  public:
    NoeudInstRepeter(Noeud* expBool, Noeud* tabInst);
   ~NoeudInstRepeter() {}
    int getValeur();
    void afficher(unsigned short indentation=0); // affiche l'opération
    void traduire(unsigned short indentation=0); // affiche l'opération
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstPour : public NoeudBoucle {
// classe pour représenter un noeud "pour (aff;cond;aff)..finpour"
// Elle est composé de 4 fils :
//    - l'expression booléenne de boucle
//    - la séquence d'instructions de la boucle
//    - l'affectation initiale
//    - l'affectation à chaque pas de la boucle
  public:
    NoeudInstPour(Noeud* expBool, Noeud* tabInst, Noeud* affect, Noeud* affectInc);
   ~NoeudInstPour() {}
    int getValeur();
    void afficher(unsigned short indentation=0);
    void traduire(unsigned short indentation=0);

  private:
    Noeud* affect;
    Noeud* affectInc;
};

/////////////////////////////////////////////////////////////////////////
class NoeudInstLire : public Noeud {
// classe pour représenter un noeud "Lire (..)"
// Elle est composé de 1 fil :
//    - la variable
  public:
     NoeudInstLire(Noeud* variable);
    ~NoeudInstLire() {}
    int getValeur();
    void afficher(unsigned short indentation=0);
    void traduire(unsigned short indentation=0);

  private:
    Noeud* variable;
};

/////////////////////////////////////////////////////////////////////////
class NoeudInstEcrire : public Noeud {
// classe pour représenter un noeud "Ecrire (..)"
// Elle est composé de 1 fil :
//    - l'expression
  public:
     NoeudInstEcrire(Noeud* expChaine);
    ~NoeudInstEcrire() {}
    int getValeur();
    void afficher(unsigned short indentation=0);
    void traduire(unsigned short indentation=0);

  private:
    Noeud* expChaine;
};

#endif /* ARBRE_H_ */
